#ifdef _FNT_SESSION_OPTIONS_H_

SessionLoadingOptions* SessionLoadingOptions::_instance{nullptr};
OptionsPage* OptionsPage::sessionLoadingOptions() {
	return SessionLoadingOptions::instance();
}

SessionLoadingOptions::SessionLoadingOptions():
	OptionsPage{"Loading", "Imaging data loading settings"},
	sp{nullptr}, disabled{true}
{
	auto options=Tracer::instance()->options();
	if(!options->getDouble("loading.radius", &sightDef)) {
		sightDef=100.0;
	}
	
	auto flayout=new QFormLayout{};
	layout()->addLayout(flayout, 0);
	layout()->addStretch(1);

	spin=new QDoubleSpinBox{this};
	flayout->addRow("&Radius:", spin);
	spin->setDecimals(1);
	spin->setMaximum(1000); // XXX
	spin->setMinimum(10);
	spin->setSingleStep(10);
	spin->setSuffix("µm");
	spin->setValue(sightDef);
	sightSet=sightDef;
	spin->setToolTip("Specify how much data to load around current position.\nLarge value results in more main memory and GPU memory consumption.");
	connect(spin, static_cast<void (QDoubleSpinBox::*)(double)>(&QDoubleSpinBox::valueChanged), this, &SessionLoadingOptions::sightChanged);
}
SessionLoadingOptions::~SessionLoadingOptions() {
}

void SessionLoadingOptions::getState(bool* a, bool* b, bool* c, bool* d) const {
	*c=*d=sightSet!=sightDef;

	if(sp) {
		bool changed=sightSet!=sp->sight;
		*a=changed && !disabled;
		*b=changed;
	} else {
		*a=false;
		*b=false;
	}
}
void SessionLoadingOptions::setStateImp(SessionState ts) {
	switch(ts) {
		case SessionState::Invalid:
		case SessionState::LoadingCatalog:
		case SessionState::Readonly:
			disabled=true;
			break;
		case SessionState::Ready:
		case SessionState::LoadingCubes:
			disabled=false;
			break;
		case SessionState::Computing:
			disabled=false;
			break;
	}
}
void SessionLoadingOptions::useDefaultImp() {
	if(sightSet!=sightDef)
		spin->setValue(sightDef);
}
void SessionLoadingOptions::saveDefaultImp() {
	auto options=Tracer::instance()->options();
	if(sightSet!=sightDef) {
		sightDef=sightSet;
		options->setDouble("loading.radius", sightDef);
	}
}
void SessionLoadingOptions::applyChangesImp() {
	if(sp && !disabled) {
		if(sightSet!=sp->sight) {
			sp->sight=sightSet;
			if(sp->loadDataAuto)
				sp->startDownloadCube();
		}
	}
}
void SessionLoadingOptions::resetChangesImp() {
	if(sp) {
		if(sightSet!=sp->sight) {
			spin->setValue(sp->sight);
		}
	}
}
void SessionLoadingOptions::sightChanged(double v) {
	sightSet=v;
	notifyChange();
}

void SessionLoadingOptions::config(SessionPriv* _vp, Options* options) const {
	if(!options->getDouble("loading.radius", &_vp->sight))
		_vp->sight=sightDef;
}
void SessionLoadingOptions::saveConfig(SessionPriv* _vp, Options* options) const {
	options->setDouble("loading.radius", _vp->sight);
}
void SessionLoadingOptions::attach(SessionPriv* _vp) {
	sp=_vp;
	if(sp) {
		if(sightSet!=sp->sight) {
			spin->setValue(sp->sight);
		}
	}
}

SessionChannelOptions* SessionChannelOptions::_instance{nullptr};
OptionsPage* OptionsPage::sessionChannelOptions() {
	return SessionChannelOptions::instance();
}

SessionChannelOptions::SessionChannelOptions():
	OptionsPage{"Channel", "Channel mapping settings"},
	sp{nullptr}, disabled{true}, disabled_xfunc_cube{true}
{
	for(int i=0; i<3; i++) {
		gboxes[i]=new QGroupBox{QString{"Group %1"}.arg(i+1), this};
		layout()->addWidget(gboxes[i], 0);
		auto glayout=new QGridLayout{gboxes[i]};
		for(int j=0; j<3; j++) {
			auto label=new QLabel{QString{"Channel %1"}.arg(j+1), gboxes[i]};
			glayout->addWidget(label, j, 0, 1, 1);
			comboBoxes[i*3+j]=new QComboBox{gboxes[i]};
			glayout->addWidget(comboBoxes[i*3+j], j, 1, 1, 1);
			comboBoxes[i*3+j]->setEditable(false);
			comboBoxes[i*3+j]->setCurrentIndex(-1);
			mapsSet[i*3+j]=-1;
			xfuncWidgets[i*3+j]=new XfuncWidget{gboxes[i]};
			glayout->addWidget(xfuncWidgets[i*3+j], j, 2, 1, 1);
			connect(comboBoxes[i*3+j], static_cast<void(QComboBox::*)(int)>(&QComboBox::currentIndexChanged), [this, i, j](int v) { this->mapChanged(i*3+j, v); });
			connect(xfuncWidgets[i*3+j], &XfuncWidget::changed, [this, i, j]() { this->xfuncChanged(i*3+j); });
		}
		glayout->setColumnStretch(1, 1);
	}
	layout()->addStretch(1);
}
SessionChannelOptions::~SessionChannelOptions() {
}

void SessionChannelOptions::getState(bool* a, bool* b, bool* c, bool* d) const {
	*c=*d=false;
	if(sp) {
		bool changed=false;
		for(int i=0; i<9; i++) {
			if(sp->cube_maps[i]!=mapsSet[i]) {
				changed=true;
				break;
			}
		}
		*a=changed && !disabled;
		*b=changed;
	} else {
		*a=false;
		*b=false;
	}
}
void SessionChannelOptions::setItems() {
	xfuncsSaved.resize(sp->channels.size());
	auto options=&sp->options;
	for(int i=0; i<sp->channels.size(); i++) {
		if(!options->getXfunc(QString{"channel.xfunc.%1"}.arg(i), &xfuncsSaved[i].first, &xfuncsSaved[i].second)) {
			xfuncsSaved[i].first=0.0;
			xfuncsSaved[i].second=1.0;
		}
	}
	for(int i=0; i<9; i++) {
		auto b=comboBoxes[i]->blockSignals(true);
		comboBoxes[i]->clear();
		for(int j=0; j<sp->channels.size(); j++) {
			comboBoxes[i]->addItem(sp->channels[j]);
		}
		comboBoxes[i]->setCurrentIndex(sp->cube_maps[i]);
		mapsSet[i]=sp->cube_maps[i];
		comboBoxes[i]->blockSignals(b);
	}
}
void SessionChannelOptions::setStateImp(SessionState ts) {
	auto prevs=sstate;
	sstate=ts;
	bool setitems=false;
	switch(ts) {
		case SessionState::Invalid:
		case SessionState::LoadingCatalog:
		case SessionState::Readonly:
			disabled=true;
			disabled_xfunc_cube=true;
			break;
		case SessionState::Ready:
			if(prevs==SessionState::LoadingCatalog)
				setitems=true;
		case SessionState::LoadingCubes:
			disabled=false;
			disabled_xfunc_cube=false;
			break;
		case SessionState::Computing:
			disabled=false;
			disabled_xfunc_cube=true;
			break;
	}
	if(setitems && sp) {
		setItems();
	}
	for(int i=0; i<9; i++) {
		xfuncWidgets[i]->setEnabled(mapsSet[i] && (disabled || !disabled_xfunc_cube));
	}
}
void SessionChannelOptions::useDefaultImp() {
}
void SessionChannelOptions::saveDefaultImp() {
}
void SessionChannelOptions::applyChangesImp() {
	if(sp && !disabled) {
		bool changed=false;
		for(int i=0; i<9; i++) {
			if(sp->cube_maps[i]!=mapsSet[i]) {
				sp->updateCube(i, mapsSet[i], xfuncsSaved[mapsSet[i]]);
				changed=true;
			}
		}
		if(changed && sp->loadDataAuto)
			sp->startDownloadCube();
	}
}
void SessionChannelOptions::resetChangesImp() {
	if(sp) {
		for(int i=0; i<9; i++) {
			if(sp->cube_maps[i]!=mapsSet[i]) {
				comboBoxes[i]->setCurrentIndex(sp->cube_maps[i]);
			}
		}
	}
}
void SessionChannelOptions::mapChanged(int i, int v) {
	if(mapsSet[i]>0)
		xfuncsSaved[mapsSet[i]]=xfuncWidgets[i]->positions();
	mapsSet[i]=v;
	if(mapsSet[i]>0) {
		xfuncWidgets[i]->setPositions(xfuncsSaved[v].first, xfuncsSaved[v].second);
		xfuncWidgets[i]->setEnabled(true);
	} else {
		xfuncWidgets[i]->setEnabled(false);
	}
	notifyChange();
}
void SessionChannelOptions::xfuncChanged(int i) {
	if(sp && !disabled) {
		if(!disabled_xfunc_cube) {
			sp->updateXfunc(i, xfuncWidgets[i]->positions());
			sp->viewer->update();
		}
	}
	notifyChange();
}

void SessionChannelOptions::config(SessionPriv* _vp, Options* options) const {
	for(int i=0; i<9; i++) {
		if(!options->getInt(QString{"channel.map.%1"}.arg(i), &_vp->cube_maps[i]))
			_vp->cube_maps[i]=i>0?0:1;
		if(!options->getXfunc(QString{"channel.xfunc.%1"}.arg(_vp->cube_maps[i]), &_vp->xfuncs[i].first, &_vp->xfuncs[i].second)) {
			_vp->xfuncs[i].first=0.0;
			_vp->xfuncs[i].second=1.0;
		}
	}
}
void SessionChannelOptions::saveConfig(SessionPriv* _vp, Options* options) const {
	for(int i=0; i<9; i++) {
		if(_vp->cube_maps[i]>0) {
			options->setInt(QString{"channel.map.%1"}.arg(i), _vp->cube_maps[i]);
			options->setXfunc(QString{"channel.xfunc.%1"}.arg(_vp->cube_maps[i]), _vp->xfuncs[i].first, _vp->xfuncs[i].second);
		} else {
			options->removeKey(QString{"channel.map.%1"}.arg(i));
		}
	}
}
void SessionChannelOptions::saveXfuncs(SessionPriv* _vp) {
	auto options=&_vp->options;
	for(int i=0; i<xfuncsSaved.size(); i++) {
		options->setXfunc(QString{"channel.xfunc.%1"}.arg(i), xfuncsSaved[i].first, xfuncsSaved[i].second);
	}
}
void SessionChannelOptions::attach(SessionPriv* _vp) {
	if(sp) {
		saveXfuncs(sp);
	}
	sp=_vp;
	if(sp) {
		sstate=sp->state;
		setItems();
		for(int i=0; i<3; i++)
			gboxes[i]->setEnabled(true);
	} else {
		for(int i=0; i<3; i++)
			gboxes[i]->setEnabled(false);
	}
}

#endif
